#include "TurnGenerator.h"
#include "ZStream.h"
#include "RandomSystem.h"
#include "StlStringAndStreams.h"

void TurnGenerator::GetTurnNumber(const unsigned int i_turn_numb, Couples& o_out)  const 
{
	const unsigned int isize(m_data.size());
	assert(i_turn_numb < 2*isize);

	if (i_turn_numb<isize) 
	{
		o_out = m_data[i_turn_numb];
	}
	else
	{
		o_out.clear();
		o_out.reserve(isize/2);

		for (unsigned int i=0; i<=(isize/2); ++i)
		{
			Couple c(m_data[i_turn_numb-isize][i].second,m_data[i_turn_numb-isize][i].first);
			o_out.push_back(c);
		}
	}
}

void TurnGenerator::Clear()
{
	m_data.clear();
}

void TurnGenerator::Initialize(const size_t i_numTeams)
{
	IntVec teamvec(i_numTeams+1); // in order to have size == numTeams and capacity = size+1; see ***
	IntVec homes(i_numTeams);
	
	for (unsigned int i=0; i<i_numTeams; ++i)
	{
		teamvec[i] = i;
		homes[i] = 0;
	}
	
	teamvec.pop_back(); // *** here we have size == numTeam and capacity = size+1
	
	//build the half m_data using roundrobin algorithm
	Couples coup(i_numTeams/2);
	
	m_data.clear();
	m_data.reserve(i_numTeams-1);

	for (unsigned int j=0; j<i_numTeams-1; ++j)
	{
		for (unsigned int i=0; i<i_numTeams/2; ++i)
		{
			const int k = -1+i_numTeams-i;
			if((homes[teamvec[i]] < homes[teamvec[k]]) || ((homes[teamvec[i]] == homes[teamvec[k]]) && (Rand()%256<128)))
			{
				coup[i] = Couple(teamvec[i], teamvec[k]);
				++homes[teamvec[i]];
			}else{
				coup[i] =	Couple(teamvec[k], teamvec[i]);
				++homes[teamvec[k]];
			}
		}
		m_data.push_back (coup);

		teamvec.insert(teamvec.begin()+1, teamvec.back()); // *** here we use the fact that capacity is size+1 so the vector must not be reallocated when inserted the elem
		teamvec.pop_back();
	}
}

ZStream& TurnGenerator::Serialize(ZStream& o_stream) const
{
	o_stream.WriteAttribute("Turns", m_data.size());

	for(STL::vector<Couples>::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
	{
		o_stream.WriteAttribute("Day", (*it));
	}

	return o_stream;
}

ZStream& TurnGenerator::Deserialize(ZStream& i_stream)
{
	size_t turns;
	i_stream.ReadAttribute(turns);

	m_data.clear();
	m_data.reserve(turns);
	Couples couples;
	for(size_t i = 0; i < turns; ++i)
	{
		i_stream.ReadAttribute(couples);
		m_data.push_back(couples);
		couples.clear();
	}

	return i_stream;
}
